#include "GameRes.h"
#include <sstream>

ResManager* ResManager::__instance = nullptr;

USING_NS_CC;

#define GameLog(format,...)	CCLOG(format,##__VA_ARGS__)

ResManager::ResManager()
{

}

ResManager::~ResManager()
{

}

ResManager* ResManager::GetInstance(void)
{
	if (!__instance) 
		__instance = new ResManager;
	return __instance;
}

void ResManager::Release(void)
{
	if (__instance) {
		delete __instance;
		__instance = nullptr;
	}
}

void ResManager::SetResPath(const char* path)
{
	_filePath = path;
	if (_filePath.back() != '\\')
		_filePath.push_back('\\');
}

const char* ResManager::GetResPath(void) const
{
	return _filePath.c_str();
}

bool ResManager::AddWdfRes(const char* fileName)
{
	std::stringstream ss;
	ss << _filePath;
	ss << fileName;
	XY_Wdf* p = new XY_Wdf;
	if (!p->Open(ss.str().c_str())) {
		return false;
	}
	uint32_t fileCount;
	const auto* pInfo = p->GetInfo(fileCount);
	for (uint32_t i = 0;i < fileCount;++i) {
		const auto& info = pInfo[i];
		WFile wFile;
		wFile.handle = p;
		wFile.info = info;
		_wasFile.insert(std::make_pair(info.uid, wFile));
	}
	return true;
}

XY_Wdf::WdfFile ResManager::GetWDFFile(uint32_t uid)
{
	XY_Wdf::WdfFile file;
	auto iter = _wasFile.find(uid);
	if (iter != _wasFile.end()) {
		auto* pInfo = &iter->second.info;
		auto* handle = iter->second.handle;
		file.pData = new unsigned char[pInfo->size];
		file.size = pInfo->size;
		std::ifstream* fStr = handle->GetStream();
		fStr->seekg(pInfo->offset, std::ios::beg);
		fStr->read((char*)file.pData, file.size);
	}
	return file;
}

cocos2d::Texture2D* ResManager::GetTexture(uint32_t uid, bool cache, const std::vector<XY_Was::Wpal>* wpal)
{
	std::string key = StringUtils::format("%08x", uid);
	Texture2D* tex = nullptr;
	if (cache) {
		tex = Director::getInstance()->getTextureCache()->getTextureForKey(key);
	}
	if (tex) return  tex;
	auto wFile = GetWDFFile(uid);
	if (!wFile) {
		GameLog("res unknown,uid:0x%08X.", uid);
		return nullptr;
	}
	XY_Was was;
	if (!was.Load(wFile.pData, wFile.size, true, wpal)) {
		GameLog("res parse error,uid:0x%08X.", uid);
		return nullptr;
	}
	const auto* pFrame = &was.GetFrames()[0];
	auto* img = new Image;
	img->autorelease();
	if (!img->initWithImageData(pFrame->clrTable, pFrame->size)) {
		GameLog("res invalid data.uid:0x%08X", uid);
		return nullptr;
	}
	if (cache) {
		tex = Director::getInstance()->getTextureCache()->addImage(img, key);
	}else{
		tex = new Texture2D;
		tex->initWithImage(img);
	}
	tex->autorelease();
	return tex;
}

cocos2d::Animate* ResManager::GetAnimate(uint32_t uid, float delay, const std::vector<XY_Was::Wpal>* wpal)
{
	auto wFile = GetWDFFile(uid);
	if (!wFile) {
		GameLog("res unknown,uid:0x%08X.", uid);
		return nullptr;
	}
	XY_Was was;
	if (!was.Load(wFile.pData, wFile.size, true, wpal)) {
		GameLog("res parse error,uid:0x%08X.", uid);
		return nullptr;
	}
	const auto* pHeader = was.GetHeader();
	const auto* pFrames = was.GetFrames();

	Vector<SpriteFrame*> frames;

	int nFrame = pHeader->numFrame;
	for (int i = 0;i < nFrame;++i) {
		const auto* pFrame = &pFrames[i];
		auto* img = new Image;
		img->autorelease();
		if (!img->initWithImageData(pFrame->clrTable, pFrame->size)) {
			GameLog("res invalid data.uid:0x%08X", uid);
			return nullptr;
		}
		auto* tex = new Texture2D;
		tex->initWithImage(img);
		tex->autorelease();
		auto* sprFrame = SpriteFrame::createWithTexture(tex, Rect(Vec2::ZERO, Size(pFrame->header.width, pFrame->header.height)));
		sprFrame->setAnchorPoint(Vec2((float)pFrame->header.centerX / (float)pFrame->header.width, 1.0f - (float)pFrame->header.cneterY / (float)pFrame->header.height));
		frames.pushBack(sprFrame);
	}
	return Animate::create(Animation::createWithSpriteFrames(frames, delay));
}

std::vector<cocos2d::Animate*> ResManager::GetAnimateSequene(uint32_t uid, float delay, bool& err, const std::vector<XY_Was::Wpal>* wpal)
{
	err = true;
	std::vector<cocos2d::Animate*> result;

	auto wFile = GetWDFFile(uid);
	if (!wFile) {
		GameLog("res unknown,uid:0x%08X.", uid);
		return result;
	}
	XY_Was was;
	if (!was.Load(wFile.pData, wFile.size, true, wpal)) {
		GameLog("res parse error,uid:0x%08X.", uid);
		return result;
	}
	const auto* pHeader = was.GetHeader();
	const auto* pFrames = was.GetFrames();

	int index = 0;
	for (int dir = 0;dir < pHeader->numDir;++dir) {
		Vector<SpriteFrame*> frames;

		int nFrame = pHeader->numFrame;
		for (int i = 0;i < nFrame;++i) {
			const auto* pFrame = &pFrames[index++];
			auto* img = new Image;
			img->autorelease();
			if (!img->initWithImageData(pFrame->clrTable, pFrame->size)) {
				GameLog("res invalid data.uid:0x%08X", uid);
				return result;
			}
			auto* tex = new Texture2D;
			tex->initWithImage(img);
			tex->autorelease();
			auto* sprFrame = SpriteFrame::createWithTexture(tex, Rect(Vec2::ZERO, Size(pFrame->header.width, pFrame->header.height)));
			sprFrame->setAnchorPoint(Vec2((float)pFrame->header.centerX / (float)pFrame->header.width, 1.0f - (float)pFrame->header.cneterY / (float)pFrame->header.height));
			frames.pushBack(sprFrame);
		}
		result.push_back(Animate::create(Animation::createWithSpriteFrames(frames, delay)));
	}
	err = false;
	return result;
}
